import json
import logging
from decimal import Decimal

from django.core.paginator import Paginator, EmptyPage
from django.db import transaction
from django.http import HttpResponseForbidden, JsonResponse
from django.shortcuts import render

# Create your views here.
from django.utils import timezone
from django.views import View
from django_redis import get_redis_connection

from goods.models import SKU
from meiduo_mall.utils.response_code import RETCODE
from order import constants
from order.models import OrderInfo, OrderGoods
from users.models import Address
from users.utils import LoginRequireMixin

logger = logging.getLogger('django')
# 支付宝测试账号
# duvkji4476@sandbox.com
# 111111

class OrderCommentView(LoginRequireMixin,View):
    def get(self,request):
        # 提供评价页面
        order_id = request.GET.get('order_id')
        order = OrderInfo.objects.get(order_id=order_id)
        order_goods = order.skus.all()
        skus = []
        for good in order_goods:
            skus.append({
                "order_id": order_id,
                "sku_id": good.sku.id,
                "name":good.sku.name,
                "price": str(good.sku.price),
                "display_score": good.score,
                "default_image": good.sku.default_image.url,
                "url":"/detail/%s/" % good.sku.id

            })
        context = {
            'skus':skus
        }
        return render(request, 'goods_judge.html',context)

    def put(self,request):
        # 修改评价
        json_dict = json.loads(request.body.decode())
        order_id = json_dict['order_id']
        sku_id = json_dict['sku_id']
        comment = json_dict['comment']
        score = json_dict['score']
        is_anonymous = json_dict['is_anonymous']
        order = OrderInfo.objects.get(order_id=order_id)
        order_good = order.skus.get(sku_id=sku_id)
        order_good.comment = comment
        order_good.score = score
        order_good.is_anonymous = is_anonymous
        order_good.save()
        # 修改sku评论数
        num = order_good.sku.comments
        order_good.sku.comments = num+1
        order_good.sku.save()
        # 修改订单状态
        order.status = OrderInfo.ORDER_STATUS_ENUM['UNSEND']
        order.save()
        return JsonResponse({'code':RETCODE.OK,'errmsg':'评论成功'})



class UserOrderInfoView(LoginRequireMixin, View):
    """我的订单"""

    def get(self,request,page_num):
        """提供我的订单页面"""
# TODO:创建我的订单页面，并渲染
        user = request.user
        # 查询
        orders = user.orderinfo_set.all().order_by('-create_time')
        if not orders:
            return HttpResponseForbidden('订单量不存在')
        for order in orders:
            # 绑定订单状态
            order.status_name = OrderInfo.ORDER_STATUS_CHOICES[(order.status-1)][1]
            order.sku_list = []
            # 查询订单商品
            order_goods = order.skus.all()
            for order_good in order_goods:
                sku = order_good.sku
                sku.count = order_good.count
                sku.amount = sku.price * sku.count
                order.sku_list.append(sku)

        # 分页
        page_num = int(page_num)
        try:
            paginator = Paginator(orders,constants.ORDERS_LIST_LIMIT)
            page_orders = paginator.page(page_num)
            total_page = paginator.num_pages
        except EmptyPage:
            return HttpResponseForbidden('订单量不存在')

        context = {
            'page_orders':page_orders,
            'total_page':total_page,
            'page_num':page_num,
        }
        return render(request,'user_center_order.html',context)

class OrderSuccessView(LoginRequireMixin, View):
    """提交订单成功"""

    def get(self, request):
        order_id = request.GET.get('order_id')
        payment_amount = request.GET.get('payment_amount')
        pay_method = request.GET.get('pay_method')

        context = {
            'order_id':order_id,
            'payment_amount':payment_amount,
            'pay_method':pay_method
        }
        return render(request, 'order_success.html', context)


class OrderCommitView(LoginRequireMixin,View):
    """提交订单"""

    def post(self,request):
        """保存订单信息和订单商品信息"""
        # 接受参数
        json_dict = json.loads(request.body.decode())
        address_id = json_dict['address_id']
        pay_method = json_dict['pay_method']

        # 校验
        if not all([address_id,pay_method]):
            return HttpResponseForbidden('缺少必要参数')
        try:
            address = Address.objects.get(id=address_id)
        except Exception:
            return HttpResponseForbidden('参数address_id参数有误')
        if pay_method not in [OrderInfo.PAY_METHODS_ENU['CASH'],OrderInfo.PAY_METHODS_ENU['ALIPAY']]:
            return HttpResponseForbidden('参数pay_method错误')
        # 开启事务，因为ＭｙＳＱＬ默认执行一句开启一个事务，所有我们需要指定一个事务
        with transaction.atomic():
            # 保存点
            save_id = transaction.savepoint()
            # 暴力回滚
            try:
                user = request.user
                # 生成订单编号
                order_id = timezone.localtime().strftime('%Y%m%d%H%M%S') + ('%09d' % user.id)
                order = OrderInfo.objects.create(
                    order_id = order_id,
                    user = user,
                    address = address,
                    total_count = 0,
                    total_amount = Decimal('0'),
                    freight = Decimal('10.00'),
                    pay_method = pay_method,
                    status = OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENU['ALIPAY'] else OrderInfo.ORDER_STATUS_ENUM['UNSEND'],
                )

                # 保存订单商品信息
                redis_conn = get_redis_connection('carts')
                redis_cart = redis_conn.hgetall('carts_%s' % user.id)
                selected = redis_conn.smembers('selected_%s' % user.id)
                carts = {}
                for sku_id in selected:
                    carts[int(sku_id)] = int(redis_cart[sku_id])

                sku_ids = carts.keys()
                for sku_id in sku_ids:
                    while True:
                        sku = SKU.objects.get(id=sku_id) # 查询最新的信息,因为stock是时时变化的，如果使用filter会有缓存，导致数据不对。
                        sku_count = carts[sku.id]
                        # 乐观锁
                        origin_stock = sku.stock
                        origin_sales = sku.sales
                        if sku_count > origin_stock:
                            # 失败回滚
                            transaction.savepoint_rollback(save_id)
                            return JsonResponse({'code':RETCODE.STOCKERR,'errmsg':'库存不足'})
                        # sku较少库存量,乐观锁更新
                        # sku.stock -= sku_count
                        # sku.sales += sku_count
                        # sku.save()
                        new_stock = origin_stock - sku_count
                        new_sales = origin_stock + sku_count
                        result = SKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock,sales=new_sales)
                        if result == 0:
                            # 返回0,表示有资源争夺，我们让用户继续下单，直到存库不足。
                            continue
                        # 修改spu销量
                        sku.spu.sales += sku_count
                        sku.spu.save()
                        # 保存订单商品信息
                        OrderGoods.objects.create(
                            order = order,
                            sku = sku,
                            count = sku_count,
                            price = sku.price,
                        )
                        order.total_count += sku_count
                        order.total_amount += (sku_count*sku.price)
                        # 下单成功，结束循环
                        break
                #添加邮费与保存订单信息
                order.total_amount += order.freight
                order.save()
            except Exception as e:
                logger.error(e)
                # 失败回滚
                transaction.savepoint_rollback(save_id)
                return JsonResponse({'code': RETCODE.DBERR, 'errmsg': '下单失败'})
            # 提交事务
            transaction.savepoint_commit(save_id)

        # 清楚购物车已结算的信息
        pl = redis_conn.pipeline()
        pl.hdel('carts_%s' % user.id,*selected)
        pl.srem('selected_%s' %user.id,*selected)
        pl.execute()

        return JsonResponse({'code':RETCODE.OK,'errmsg':'下单成功','order_id':order.order_id})


class OrderSettlementView(LoginRequireMixin,View):
    """结算订单"""


    def get(self,request):
        """提供订单结算页面"""

        user = request.user
        # 查询地址
        try:
            addresses = Address.objects.filter(user = user,is_deleted=False)
        except Address.DoesNotExist:
            # 如果地址为空，渲染模板时会判断，并跳转到地址编辑页面
            addresses = None

        # 从购物车中查询出被勾选的信息
        redis_conn = get_redis_connection('carts')
        redis_cart = redis_conn.hgetall('carts_%s' % user.id)
        cart_selected = redis_conn.smembers('selected_%s' % user.id)
        cart = {}
        for sku_id in cart_selected:
            cart[int(sku_id)] = int(redis_cart[sku_id])

        # 准备初始值
        total_count = 0
        total_amount = Decimal(0.00)
        # 查询商品信息
        skus = SKU.objects.filter(id__in = cart.keys())

        for sku in skus:
            sku.count = cart[sku.id]
            sku.amount = sku.count * sku.price
            total_count += sku.count
            total_amount +=sku.count * sku.price
        # 运费
        freight = Decimal('10.00')
        # 渲染页面
        context = {
            'addresses':addresses,
            'skus':skus,
            'total_count':total_count,
            'total_amount':total_amount,
            'freight':freight,
            'payment_amount':total_amount+freight
        }

        return render(request,'place_order.html',context)
